package ide.vista;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

public class PanelPasoAPaso {
	private JPanel panel;
	private JScrollPane scroll;
	private JPanel panelDeContenido;
	private JLabel instruccionActual;
	private ArrayList<JLabel> instruccionesSiguientes;
	private JTable tablaEstadosAnteriores;
	private JTable tablaEstadosActuales;
	private JTable tablaFlagsAnteriores;
	private JTable tablaFlagsActuales;
	private JTable tablaMemoria;

	public PanelPasoAPaso() {
		this.panel = new JPanel(new BorderLayout());
		this.panel.setVisible(false);

		this.panelDeContenido = new JPanel(new GridBagLayout());

		this.scroll = new JScrollPane(this.panelDeContenido, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		this.panel.add(this.scroll, BorderLayout.CENTER);

		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.VERTICAL;

		JLabel label = new JLabel("Ultima instruccion ejecutada");
		c.gridx = 0;
		c.gridy = 0;
		c.gridwidth = 4;
		this.panelDeContenido.add(label, c);

		this.instruccionActual = new JLabel("");
		Font font = this.instruccionActual.getFont();
		Font boldFont = new Font(font.getFontName(), Font.ITALIC, font.getSize());
		this.instruccionActual.setFont(boldFont);
		this.instruccionActual.setForeground(Color.RED);
		c.gridx = 0;
		c.gridy = 1;
		c.gridwidth = 4;
		this.panelDeContenido.add(this.instruccionActual, c);

		this.instruccionesSiguientes = new ArrayList<JLabel>();
		JLabel labelSiguiente = new JLabel("");
		c.gridx = 0;
		c.gridy = 2;
		this.panelDeContenido.add(labelSiguiente, c);
		this.instruccionesSiguientes.add(labelSiguiente);
		labelSiguiente = new JLabel("");
		c.gridx = 0;
		c.gridy = 3;
		this.panelDeContenido.add(labelSiguiente, c);
		this.instruccionesSiguientes.add(labelSiguiente);
		labelSiguiente = new JLabel("");
		c.gridx = 0;
		c.gridy = 4;
		c.insets = new Insets(0, 0, 20, 0); // top padding
		this.panelDeContenido.add(labelSiguiente, c);
		this.instruccionesSiguientes.add(labelSiguiente);

		label = new JLabel("Registros", SwingConstants.CENTER);
		c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = 5;
		c.gridwidth = 5;
		this.panelDeContenido.add(label, c);

		label = new JLabel("Estado Anterior");
		c.gridx = 0;
		c.gridy = 6;
		c.gridwidth = 2;
		this.panelDeContenido.add(label, c);

		label = new JLabel("Estado Actual");
		c.gridx = 3;
		c.gridy = 6;
		c.gridwidth = 1;
		this.panelDeContenido.add(label, c);

		c.gridx = 0;
		c.gridy = 7;
		c.insets = new Insets(0, 0, 0, 20); // top padding
		List<String> places = Arrays.asList("00", "00");
		this.tablaEstadosAnteriores = this.crearEstadosRegistros(places);
		this.panelDeContenido.add(this.tablaEstadosAnteriores, c);

		c.gridx = 3;
		c.gridy = 7;
		List<String> places2 = Arrays.asList("00", "00");
		this.tablaEstadosActuales = this.crearEstadosRegistros(places2);
		this.panelDeContenido.add(this.tablaEstadosActuales, c);

		label = new JLabel("ALU", SwingConstants.CENTER);
		c.gridx = 0;
		c.gridy = 8;
		c.gridwidth = 5;
		c.insets = new Insets(20, 0, 0, 0); // top padding
		this.panelDeContenido.add(label, c);

		c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = 9;
		c.gridwidth = 2;
		c.insets = new Insets(0, 0, 0, 20); // top padding
		this.tablaFlagsAnteriores = this.crearTablaFlags();
		this.panelDeContenido.add(this.tablaFlagsAnteriores, c);

		c.gridx = 3;
		c.gridy = 9;
		this.tablaFlagsActuales = this.crearTablaFlags();
		this.panelDeContenido.add(this.tablaFlagsActuales, c);

		this.tablaMemoria = this.crearTablaMemoria();
		JPanel panelTabla = new JPanel(new BorderLayout());
		panelTabla.add(new JLabel("Memoria RAM"), BorderLayout.NORTH);
		panelTabla.add(this.tablaMemoria, BorderLayout.SOUTH);
		JScrollPane scrollLeft = new JScrollPane(panelTabla, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		this.panel.add(scrollLeft, BorderLayout.EAST);
	}

	private JTable crearEstadosRegistros(List<String> estados) {
		@SuppressWarnings("rawtypes")
		Vector<Vector> rowData = new Vector<Vector>();
		Vector<String> columns = new Vector<String>();
		columns.addElement("Registro");
		columns.addElement("Estado");

		Iterator<String> iterator = estados.iterator();
		for (int i = 0; i < 16; i++) {
			Vector<String> rowOne = new Vector<String>();
			String val = iterator.hasNext() ? (String) iterator.next() : "00";

			rowOne.addElement("r" + i);
			rowOne.addElement(val);
			rowData.addElement(rowOne);
		}

		TableModel model = new DefaultTableModel(rowData, columns) {
			/**
			 * generado para ignorar warning
			 */
			private static final long serialVersionUID = 1L;

			public boolean isCellEditable(int row, int column) {
				return false;// This causes all cells to be not editable
			}
		};
		JTable table = new JTable(model);

		table.setPreferredSize(new Dimension(100, 260));

		return table;
	}

	public void actualizarEstadosRegistros(ArrayList<String> registros) {
		int cantidadFilas = tablaEstadosActuales.getRowCount();

		for (int i = 0; i < cantidadFilas; i++) {
			String valorAnterior = (String) tablaEstadosActuales.getValueAt(i, 1);
			tablaEstadosAnteriores.setValueAt(valorAnterior, i, 1);
			String valorNuevo = registros.get(i);
			tablaEstadosActuales.setValueAt(valorNuevo, i, 1);
		}

	}

	private JTable crearTablaFlags() {
		@SuppressWarnings("rawtypes")
		Vector<Vector> rowData = new Vector<Vector>();
		Vector<String> columns = new Vector<String>();
		columns.addElement("Flag");
		columns.addElement("Valor");

		rowData.addElement(new Vector<String>(Arrays.asList("carry", "0")));
		rowData.addElement(new Vector<String>(Arrays.asList("negativo", "0")));
		rowData.addElement(new Vector<String>(Arrays.asList("overflow", "0")));
		rowData.addElement(new Vector<String>(Arrays.asList("cero", "0")));
		rowData.addElement(new Vector<String>(Arrays.asList("perd-pre", "0")));

		TableModel model = new DefaultTableModel(rowData, columns) {
			private static final long serialVersionUID = 1L;
			public boolean isCellEditable(int row, int column) {
				return false;
			}
		};
		JTable table = new JTable(model);

		table.getColumnModel().getColumn(1).setPreferredWidth(30);
		return table;
	}

	public void actualizarFlags(int carry, int overflow, int negativo, int cero, int perdidaPrecision) {
		List<String> flags = Arrays.asList(Integer.toString(carry), Integer.toString(overflow), Integer.toString(negativo),
				Integer.toString(cero), Integer.toString(perdidaPrecision));

		for (int i = 0; i < 5; i++) {
			String carryAnterior = (String) tablaFlagsActuales.getValueAt(i, 1);
			tablaFlagsAnteriores.setValueAt(carryAnterior, i, 1);
			tablaFlagsActuales.setValueAt(flags.get(i), i, 1);
		}
	}

	private JTable crearTablaMemoria() {
		@SuppressWarnings("rawtypes")
		Vector<Vector> rowData = new Vector<Vector>();
		Vector<String> columns = new Vector<String>();
		columns.addElement("Flag");
		columns.addElement("Valor");

		for (int i = 0; i < 256; i++) {
			Vector<String> rowOne = new Vector<String>();
			rowOne.addElement("#" + i);
			rowOne.addElement("00");
			rowData.addElement(rowOne);
		}

		TableModel model = new DefaultTableModel(rowData, columns) {
			// generado para ignorar warning
			private static final long serialVersionUID = 1L;
			public boolean isCellEditable(int row, int column) {
				return false; // This causes all cells to be not editable
			}
		};
		JTable table = new JTable(model);
		table.setPreferredSize(new Dimension(80, 4096));
		return table;
	}

	public void actualizarTablaMemoria(ArrayList<String> ram) {
		int cantidadFilas = ram.size();
		for (int i = 0; i < cantidadFilas; i++) {
			tablaMemoria.setValueAt(ram.get(i), i, 1);
		}
	}

	public void setInstruccionActual(String instruccion) {
		this.instruccionActual.setText(instruccion);
	}

	public void setInstruccionesSiguientes(ArrayList<String> instrucciones) {
		for (int i = 0; i < 3; i++) {
			try {
				this.instruccionesSiguientes.get(i).setText(instrucciones.get(i));
			} catch (IndexOutOfBoundsException e) {
				this.instruccionesSiguientes.get(i).setText("");
			}
		}
	}

	public void limpiarInstrucciones() {
		this.instruccionActual.setText("");
		for (int i = 0; i < 3; i++) {
			this.instruccionesSiguientes.get(i).setText("");

		}
	}

	public JPanel getPanelPrincipal() {
		return this.panel;
	}

	public JPanel getPanelDeContenido() {
		return this.panelDeContenido;
	}

	public void ocultar() {
		this.panelDeContenido.setVisible(false);;
	}

	public void mostrar() {
		this.panelDeContenido.setVisible(true);;
	}

}
